#pragma once

#include<iostream>
#include<string>
#include<unistd.h>
#include<cerrno>
#include<cstring>
#include<strings.h>
#include<signal.h>
#include<cstdlib>
#include<functional>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>//网络头文件
#include<netinet/in.h>

namespace Server
{
   
    using namespace std;
    static const string defaultIp = "0.0.0.0";//点分十进制TODO
    static const int gnum = 1024;
    enum {UsAGE_ERR=1, SOCKET_ERR = 2, BIND_ERR, OPEN_ERR};

    typedef function<void (int, string, uint16_t ,string)> func_t;
    class udpServer
    {
    public: 
        udpServer(const func_t& cb, const uint16_t& port, const string& ip = defaultIp)
            :_callback(cb)
            ,_port(port)
            ,_ip(ip)
            ,_sockfd(-1)
        {}

        void initServer()
        {
            //1. 创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);//AFINET代表网络通信
            if(_sockfd == -1)
            {
                cerr << "socket error: " << errno << " : " << strerror(errno) << endl;
                exit(SOCKET_ERR);
            }
            cout << "socket success: " << " : " << _sockfd << endl;
            //2.绑定port, ip(TODO)
            //未来服务器要明确的port，不能随意改变
            //写服务器的是一家公司，写客户端(client)是无数家公司
            struct sockaddr_in local; //定义了一个变量，栈，用户层
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port); //你如果要给别人发消息，port和ip也需要发给对方
            //local.sin_addr.s_addr = inet_addr(_ip.c_str()); //1.string->uint32_t 2.htonl();
            local.sin_addr.s_addr = INADDR_ANY; // 任意地址bind, 服务器的真实写法
            int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));//OS绑定
            
            if(n == -1) 
            {
                cerr << "bind error: " << errno << " : " << strerror(errno) << endl;
                exit(BIND_ERR);
            }
            // UDP Server 的预备工作完成

        }

        void start()
        {
            //服务器的本质其实就是一个死循环：常驻内存的进程->OS(OS就是死循环的一个软件程序)
            char buffer[gnum];
            for(;;)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer); //必填
                ssize_t s = recvfrom(_sockfd, buffer, (sizeof buffer)-1, 0, (struct sockaddr*)&peer, &len);
                //1. 数据是什么 2. 谁发的
                if(s > 0)
                {
                    buffer[s] = 0;
                    string clientip = inet_ntoa(peer.sin_addr); //1. 网络序列 2.int->点分十进制IP
                    uint16_t clientport = ntohs(peer.sin_port);
                    string message = buffer;

                    cout << clientip << "[" << clientport << "]#" << message << endl;

                    //我们只把数据读上来就完了吗？还需要对数据做处理
                    _callback(_sockfd, clientip, clientport, message);
                }

            }
        }   

        ~udpServer()
        {

        }
    private:
        uint16_t _port;
        std::string _ip; //实际上，一款网络服务器，不建议指明一个ip
        int _sockfd;//文件描述符
        func_t _callback; //回调
    };
}
